/*************************************************************************
 * Nuvoton Electronics Corporation confidential
 *
 * Copyright (c) 2008 by Nuvoton Electronics Corporation
 * All rights reserved
 *
 * FILENAME
 *     main.c
 *
 * VERSION
 *     1.0
 *
 * DESCRIPTION
 *     NUC930 USB Host integration test program
 *
 * HISTORY
 *     2008.06.24       Created
 *
 * REMARK
 *     None
 **************************************************************************/
#ifdef ECOS
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "drv_api.h"
#include "diag.h"
#include "wbtypes.h"
#include "wbio.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wbtypes.h"
#include "wblib.h"
#endif

#include "nvtfat.h"
#include "W55FA93_reg.h"
/* USB */
#include "usb.h"
#include "usbvideo.h"
#include "usbkbd.h"
#include "nvtfat.h"

#define SYSTEM_CLOCK		12000000
#define UART_BAUD_RATE		115200

#define DUMMY_BUFFER_SIZE		(64 * 1024)

#ifdef ECOS
#define sysGetTicks(TIMER0)   cyg_current_time()
#endif


//static UINT8  _pucDummy[DUMMY_BUFFER_SIZE];


UINT8	_JpegImage[256 * 1024];
UINT8	_JpegImageR[256 * 1024];
extern UINT32	_QueuedSize;

extern INT  W99683_HasImageQueued(VOID);


void  GetJpegImage(UINT8 *image, UINT32 *len, INT interval)
{
	UINT8   *bufPTR;
	INT     bufLEN;
	UINT32	idx = 0;
	
	*len = 0;
	/* Skip frames */
	while (1)
	{
		if (W99683_GetFramePiece(&bufPTR, &bufLEN) < 0) 
			;           /* W99683 is not enabled, we wait */

		if ((bufPTR[0] == 0xFF) && (bufPTR[1] == 0xD8))
		{
			if (interval == 0)
				break;
			interval--;
		}
	}
	
	while (1)
	{	
		memcpy(&image[idx], bufPTR, bufLEN);
		idx += bufLEN;
		*len += bufLEN;
		
		if (W99683_GetFramePiece(&bufPTR, &bufLEN) < 0) 
			continue;		/* W99683 is not enabled, we wait */
		
		if ((bufPTR[0] == 0xFF) && (bufPTR[1] == 0xD8))
			return;
	}
}


static INT  Action_Compare(CHAR *suFileName1, CHAR *szAsciiName1, 
							CHAR *suFileName2, CHAR *szAsciiName2)
{
	INT		hFile1, hFile2;
	INT		nLen1, nLen2, nCount, nStatus1, nStatus2;
	UINT8	buffer1[8192], buffer2[8192];
	UINT32	nJpegLen;
	
	hFile1 = fsOpenFile(suFileName1, szAsciiName1, O_RDONLY);
	if (hFile1 < 0)
		return hFile1;
	
	hFile2 = fsOpenFile(suFileName2, szAsciiName2, O_RDONLY);
	if (hFile2 < 0)
		return hFile2;
	
	sysprintf("\nComparing file ...\n");
	nCount = 0;
	while (1)
	{
		nStatus1 = fsReadFile(hFile1, buffer1, 1024, &nLen1);
		nStatus2 = fsReadFile(hFile2, buffer2, 1024, &nLen2);

		GetJpegImage(_JpegImage, &nJpegLen, 0);
		
		if ((nStatus1 == ERR_FILE_EOF) && (nStatus2 == ERR_FILE_EOF))
		{
			sysprintf("\ncompare ok!\n");
			fsCloseFile(hFile1);
			fsCloseFile(hFile2);
			return 0;
		}
		
		if (nLen1 != nLen2)
			break;
			
		if (memcmp(buffer1, buffer2, 1024))
			break;
		
		nCount++;
		//if ((nCount % 1024) == 0)
		//	sysprintf("%d KB    \r", nCount);
	}
	
	sysprintf("\nFile Compare failed at offset %x\n", nCount * 1024);
	
	fsCloseFile(hFile1);
	fsCloseFile(hFile2);
	return -1;
}



INT  copy_file(CHAR *suSrcName, CHAR *szSrcAsciiName, 
					CHAR *suDstName, CHAR *szDstAsciiName)
{
	INT			hFileSrc, hFileDst, nByteCnt, nStatus;
	UINT8		*pucBuff, *szFNameSrc, *szFNameDst;
	UINT32		nJpegLen;

	pucBuff = (UINT8 *)malloc(4096 + MAX_FILE_NAME_LEN + 512);
	if (pucBuff == NULL)
		return ERR_NO_FREE_MEMORY;
		
	szFNameSrc = pucBuff + 4096;
	szFNameDst = szFNameSrc + MAX_FILE_NAME_LEN/2;

	hFileSrc = fsOpenFile(suSrcName, szSrcAsciiName, O_RDONLY);
	if (hFileSrc < 0)
	{
		free(pucBuff);
		return hFileSrc;
	}

	hFileDst = fsOpenFile(suDstName, szDstAsciiName, O_RDONLY);
	if (hFileDst > 0)
	{
		fsCloseFile(hFileSrc);
		fsCloseFile(hFileDst);
		free(pucBuff);
		return ERR_FILE_EXIST;
	}

	hFileDst = fsOpenFile(suDstName, szDstAsciiName, O_CREATE);
	if (hFileDst < 0)
	{
		fsCloseFile(hFileSrc);
		free(pucBuff);
		return hFileDst;
	}

   	while (1)
   	{
   		nStatus = fsReadFile(hFileSrc, pucBuff, 4096, &nByteCnt);
   		if (nStatus < 0)
   			break;

		nStatus = fsWriteFile(hFileDst, pucBuff, nByteCnt, &nByteCnt);
   		if (nStatus < 0)
   			break;

		GetJpegImage(_JpegImage, &nJpegLen, 0);
	}
	fsCloseFile(hFileSrc);
	fsCloseFile(hFileDst);
	free(pucBuff);

	if (nStatus == ERR_FILE_EOF)
		nStatus = 0;
	return nStatus;
}



INT Test()
{
	INT     nStatus;
	//CHAR	szSrcA[24] = "C:\\tape001.mpg";
	CHAR	szSrcA[24] = "C:\\1.mp4";
	CHAR	szDstA[24] = "C:\\copya";
	CHAR	suFileName1[64], suFileName2[64];
	UINT32	nJpegLen;

	while (1)
	{
		sysprintf("Delete file: %s\n", szDstA);
		fsAsciiToUnicode(szDstA, suFileName1, TRUE);
		nStatus = fsDeleteFile(suFileName1, NULL);
		if (nStatus < 0)
			sysprintf("Failed, status = %x\n", nStatus);

		while (_QueuedSize > 16*1024)
		{
			GetJpegImage(_JpegImage, &nJpegLen, 0);
			sysprintf(".");
		}

		sysprintf("Copy file: %s\n", szSrcA);
		fsAsciiToUnicode(szSrcA, suFileName1, TRUE);
		fsAsciiToUnicode(szDstA, suFileName2, TRUE);
		nStatus = copy_file(suFileName1, NULL, suFileName2, NULL);
		if (nStatus < 0)
		{
			sysprintf("Failed, status = %x\n", nStatus);
			exit(0);
		}

		sysprintf("Compare file: %s and %s\n", szSrcA, szDstA);
		fsAsciiToUnicode(szSrcA, suFileName1, TRUE);
		fsAsciiToUnicode(szDstA, suFileName2, TRUE);
		
		if (Action_Compare(suFileName1, NULL, suFileName2, NULL) < 0)
			break;
	}	
	return 0;
}


void  Isochronous_Test()
{
	CHAR    szFileName[32] = {'C',0,':',0,'\\',0,'1',0,0,0 };
	CHAR    suFileName[128];
	INT     nIdx = 0;
	UINT32	nJpegLen;
	INT    	hFile;
	INT     nWriteBytes;

	W99683Cam_Init();

	while (!W99683Cam_IsConnected())
#ifdef ECOS
		Hub_CheckIrqEvent(0);
#else	
		Hub_CheckIrqEvent();
#endif

	if (W99683Cam_Open() < 0)
	{
		sysprintf("Failed to open W99683 device!\n");
		return;           /* _W99683_Camera is freed also */
	}

	while (!W99683Cam_IsStreaming())
		;   

	/* Drop 5 pictures */
	for (nIdx = 0; nIdx < 10; nIdx++)
	//for (nIdx = 0; ; nIdx++)
	{
		sysprintf("%d GetJpegImage...\n", nIdx);
		GetJpegImage(_JpegImage, &nJpegLen, 0);
		sysprintf("ImageSize: %d, _QueuedSize: %d\n", nJpegLen, _QueuedSize);
	}
	
	//Test();
	
	//Action_WriteSpeedTest(szFileName, NULL);
	
	for (nIdx = 0; nIdx < 30; nIdx++)
	{
reget:		
		GetJpegImage(_JpegImage, &nJpegLen, 0);
		if (_QueuedSize > 200000)
		{
			goto reget;
		}
		sysprintf("ImageSize: %d, _QueuedSize: %d\n", nJpegLen, _QueuedSize);
		
		/* Open a new file for writing */
		sprintf(szFileName, "C:\\%04d.jpg", nIdx);
		fsAsciiToUnicode(szFileName, suFileName, 1);
		hFile = fsOpenFile(suFileName, NULL, O_CREATE);
		if (hFile > 0)
			sysprintf("Opene file:[%s], file handle:%d\n", szFileName, hFile);
		else
		{
			sysprintf("Failed to open file: %s (%x)\n", szFileName, hFile);
			continue;
		}
		if ((fsWriteFile(hFile, _JpegImage, nJpegLen, &nWriteBytes) < 0) ||
			(nWriteBytes != nJpegLen))
			sysprintf("File write error! %d %d\n", nWriteBytes);
		else
			sysprintf("%d bytes\n", nWriteBytes);
		fsCloseFile(hFile);
	}
	
	while (1)
		GetJpegImage(_JpegImage, &nJpegLen, 0);
}


void IntegrationTest(void)
{
	INT		t0;
	UINT32	uBlockSize, uFreeSize, uDiskSize;

	sysprintf("Please plug in pen driver, key board and W99683 camera in advance\n");

	InitUsbSystem();       
	UMAS_InitUmasDriver();
	USBKeyboardInit();
	/* wait hard disk ready */
	t0 = sysGetTicks(TIMER0);
	while (sysGetTicks(TIMER0) - t0 < 300)
		;
	
	if (fsDiskFreeSpace('C', &uBlockSize, &uFreeSize, &uDiskSize) == 0)
		sysprintf("Disk size = %d KB, Free speace = %d KB\n", uDiskSize, uFreeSize);
	else
		sysprintf("fsDiskFreeSpace failed!!\n");
	
	Isochronous_Test();
}
/* Pen driver Connect/disconnect  Test */
volatile UINT32 i32MsConnect = 0;
volatile UINT32 i32MsDisConnect = 1;
volatile UINT32 i32AccessDone = 0;
VOID MassStotrageConnection(void* umas)
{
	volatile i=0x20000;	
	sysprintf("Umas driver connect  0x%x\n", (UINT32)umas);
	i32MsConnect = 1;
	i32MsDisConnect =0;
	while(i--);	
	/* Stop Event check */
	//sysClearTimerEvent(TIMER0, usbTimerChanel);
}
VOID MassStotrageDisconnection(void* umas)
{
	sysprintf("Umas driver disconnect 0x%x\n", (UINT32)umas);

	i32MsConnect = 0;
	i32MsDisConnect = 1;
	i32AccessDone = 0;
	/* Restart Event Check */
	//usbTimerChanel = sysSetTimerEvent(TIMER0, 20, (PVOID)usbEvent);	/* 20 ticks/per sec */	
}

/*=====================================================================================
Test Condition:
	Plug in a pen driver to USBH port 1 or port 0. 



=====================================================================================*/
void PenDriverAccess(UINT32 u32Count)
{
	CHAR szFileName[32] = {'C',0,':',0,'\\',0,'1',0,0,0 };
	CHAR szAsciiStr[32]={0};
	CHAR suFileName[128];
	INT     nIdx = 0, nIdy=0;
	UINT32	nJpegLen= 256*1024;
	INT    	hFile;
	INT     nWriteBytes;
	
	sprintf(szAsciiStr, "C:\\Test");
	fsAsciiToUnicode(szAsciiStr, suFileName, TRUE);
	fsMakeDirectory(suFileName, NULL);
	//for (nIdx = 0; nIdx < 60; nIdx++)
	for (nIdx = 0; nIdx < u32Count; nIdx++)
	{	
		for (nIdy = 0; nIdy < (nJpegLen); nIdy=nIdy+1)
			_JpegImage[nIdy] = (nIdy+(nIdy>>8)+(nIdy>>16))+nIdx;
		
		sysprintf("ImageSize: %d\n", nJpegLen);		
		/* Open a new file for writing */
		sprintf(szFileName, "C:\\Test\\%07d.jpg", nIdx);
		fsAsciiToUnicode(szFileName, suFileName, 1);
		hFile = fsOpenFile(suFileName, NULL, O_CREATE);
		if (hFile > 0)
			sysprintf("Opene file:[%s], file handle:%d\n", szFileName, hFile);
		else
		{
			sysprintf("Failed to open file: %s (%x)\n", szFileName, hFile);
			continue;
		}
		if ((fsWriteFile(hFile, _JpegImage, nJpegLen, &nWriteBytes) < 0) ||
			(nWriteBytes != nJpegLen))
			sysprintf("File write error! %d %d\n", nWriteBytes);
		else
			sysprintf("%d bytes\n", nWriteBytes);
		fsCloseFile(hFile);
		hFile = fsOpenFile(suFileName, NULL, O_RDONLY );
		if (hFile > 0)
			sysprintf("Opene file:[%s], file handle:%d\n", szFileName, hFile);
		else
		{
			sysprintf("Opene file Error\n");
			while(1);
		}
		if ((fsReadFile(hFile, _JpegImageR, nJpegLen, &nWriteBytes) < 0) ||
			(nWriteBytes != nJpegLen))
			sysprintf("File read error! %d %d\n", nWriteBytes);
		fsCloseFile(hFile);		
			
		if(memcmp(_JpegImage, _JpegImageR, nJpegLen)  != 0 )
		{
			sysprintf("Compare file error\n");
			while(1);
		}	
					
	}	
	sysprintf("Done\n");
}	
void PenDriverConnectTest(void)
{
	UINT32	uBlockSize, uFreeSize, uDiskSize;
	
	umass_register_connect(MassStotrageConnection);	
	umass_register_disconnect(MassStotrageDisconnection);	
	InitUsbSystem();
	UMAS_InitUmasDriver();
	sysDelay(30);			/* Delay 300 ms */
	while(1){												
		if(i32MsConnect ==1){						
			if(i32AccessDone==0){
				if (fsDiskFreeSpace('C', &uBlockSize, &uFreeSize, &uDiskSize) == 0){
					sysprintf("Disk size = %d KB, Free speace = %d KB\n", uDiskSize, uFreeSize);
				}else{
					sysprintf("fsDiskFreeSpace failed!!\n");							
					sysprintf("Pen driver may plug out !\n");					
				}
				PenDriverAccess(1);	
				i32AccessDone = 1;
				sysprintf("Please plug out the pen driver for test\n");										
			}
		}
		if(i32MsDisConnect == 0)
			sysprintf("Please plug out the pen driver for test\n");	
		if(i32MsConnect == 0)
			sysprintf("Please plug in the pen driver for test\n");															
		Hub_CheckIrqEvent();
	}						
}

INT main()
{
	UINT32 	u32Item, u32ExtFreq;
	UINT32 	u32PllOutKHz;
	WB_UART_T uart;
#ifndef ECOS
	/* initialize UART */
	u32ExtFreq = sysGetExternalClock();

	sysSetTimerReferenceClock (TIMER0, u32ExtFreq*1000);
	sysStartTimer(TIMER0, 100, PERIODIC_MODE);

	sysDisableCache(); 	
	sysFlushCache(I_D_CACHE);		
	sysEnableCache(CACHE_WRITE_BACK);
	
	sysUartPort(1);
	uart.uiFreq = u32ExtFreq*1000;	//use APB clock
    	uart.uiBaudrate = 115200;
    	uart.uiDataBits = WB_DATA_BITS_8;
    	uart.uiStopBits = WB_STOP_BITS_1;
    	uart.uiParity = WB_PARITY_NONE;
    	uart.uiRxTriggerLevel = LEVEL_1_BYTE;
    	sysInitializeUART(&uart);    	    	

	sysSetSystemClock(eSYS_UPLL, 	//E_SYS_SRC_CLK eSrcClk,	
					192000,		//UINT32 u32PllKHz, 	
					192000,		//UINT32 u32SysKHz,
					192000,		//UINT32 u32CpuKHz,
					  192000/2,		//UINT32 u32HclkKHz,
					  192000/4);		//UINT32 u32ApbKHz
	u32PllOutKHz = sysGetPLLOutputKhz(eSYS_UPLL, u32ExtFreq);
	sysprintf("PLL out frequency %d Khz\n", u32PllOutKHz);		
	
	//outp32(0xb0000084, 0x03);
	//outp32(0xb0000230, 0x85);
	outp32(REG_AHBCLK, inp32(REG_AHBCLK) & ~USBD_CKE);
	outp32(REG_APBCLK, 0xFFFFFFFF);	
#endif

	fsInitFileSystem();

	do
	{
		sysprintf("====================================================================\n");
		sysprintf("Please select the USB host port through Transceiver ports or  GPIO 				\n");
		sysprintf("[1] Transceiver port 0													\n");
		sysprintf("[2] Transceiver port 0 and 1												\n");
		sysprintf("[3] Host-like port (GPB0 , GPB1)											\n");
		sysprintf("[4] Host-like port (GPE3 , GPE4)											\n");
		sysprintf("====================================================================\n");
		u32Item = sysGetChar();
		switch(u32Item)
		{
			case '1': 	USB_PortInit(HOST_NORMAL_PORT0_ONLY);;		break;
	    		case '2': 	USB_PortInit(HOST_NORMAL_TWO_PORT);;		break;
	    		case '3': 	USB_PortInit(HOST_LIKE_PORT0);	break;	
	    		case '4':	USB_PortInit(HOST_LIKE_PORT1);	break;	    		
		}
	}while((u32Item> '4') || (u32Item< '0'));		
	
	sysprintf("=============================================================================================\n");
	sysprintf("[1] Pen driver connect/disconect test																						\n");
	sysprintf("[2] Integration test																									\n");	
	u32Item = sysGetChar();
	switch(u32Item)
	{
		case '1': 	PenDriverConnectTest();	
				break;
		case '2':	IntegrationTest();
				break;
	}	
		
	
	return 0;
}

